Feat(playground): Add Native Sandbox Engine#291
Open
jlukic wants to merge 10 commits into
Open
Conversation
One shared tooling worker per page multiplexing all sessions (build, bare-import CDN rewriting, lazy TypeScript), a materialized-session service worker with broadcast recovery, and a headless PlaygroundProject that turns a file set into a live preview URL. Sandbox assets build self-contained so they never enter a dev server's transform pipeline.
example-preview keeps its tag and consumer contract but now owns a PlaygroundProject instead of wrapping playground-elements. Accepts a shared project setting so editor surfaces can drive the same preview. Files travel as data, so the sample/html closing-tag escaping dance is gone. Frames recover by node replacement, never reload.
Editor surface speaks filenames, strings, and plain-data markers so a future Monaco binding stays a binding. Per-file editor states preserve undo history across tab switches. Pragma regions (sui-hide/sui-fold, playground-* aliases) are display-only decorations — expanding a fold never shows the marker comment and never mutates the document. CodePlayground now drives a shared PlaygroundProject: TS completions, hover, and diagnostics compose with SUI LSP per file type, replacing the no-completions workaround.
Vendored sandbox files, the dev worker shim, the CM5-era lib files, and the upstream patch all go — the sandbox engine owns these concerns. Uninstalling drops 55 packages from docs, including the deprecated MWC and Comlink chains.
The dynamic-import case caught a real bug — es-module-lexer spans include the quotes for dynamic imports, so rewrites dropped them.
⚪ Bundle size: no meaningful change · +1513 shipped LOC for
|
| signal | result |
|---|---|
component brotli |
0 B |
| Shipped LOC | +1513 |
| Comment LOC | +175 |
| Changed bundles | 0 / 24 |
No bundle changed size. 🎉
LOC by scope: +1513 shipped LOC · +175 comment LOC
Shipped LOC excludes comments and blank lines.
| scope | shipped LOC | comment LOC |
|---|---|---|
playground |
+1513 | +175 |
All 24 bundles, gzip, and raw sizes
| bundle | group | brotli | Δ brotli | gzip | Δ gzip | raw | Δ raw |
|---|---|---|---|---|---|---|---|
compiler |
package | 6.1 KB | — | 6.8 KB | — | 18.4 KB | — |
component 🎯 |
package | 48.8 KB | — | 55.9 KB | — | 170.9 KB | — |
query |
package | 16.0 KB | — | 17.8 KB | — | 52.5 KB | — |
reactivity |
package | 7.1 KB | — | 7.8 KB | — | 22.2 KB | — |
renderer |
package | 43.2 KB | — | 49.2 KB | — | 150.9 KB | — |
specs |
package | 53.9 KB | — | 63.8 KB | — | 236.3 KB | — |
tailwind |
package | 67.3 KB | — | 85.3 KB | — | 335.3 KB | — |
templating |
package | 28.8 KB | — | 32.3 KB | — | 95.9 KB | — |
utils † |
package | 17.6 KB | — | 19.7 KB | — | 50.9 KB | — |
framework |
framework | 130.1 KB | — | 166.0 KB | — | 698.5 KB | — |
button |
primitive | 12.0 KB | — | 15.2 KB | — | 128.6 KB | — |
card |
primitive | 3.0 KB | — | 3.5 KB | — | 15.8 KB | — |
container |
primitive | 694 B | — | 888 B | — | 2.4 KB | — |
divider |
primitive | 1.6 KB | — | 1.9 KB | — | 6.5 KB | — |
icon |
primitive | 26.3 KB | — | 35.0 KB | — | 143.7 KB | — |
image |
primitive | 776 B | — | 993 B | — | 2.2 KB | — |
input |
primitive | 3.9 KB | — | 4.5 KB | — | 15.6 KB | — |
label |
primitive | 1.3 KB | — | 1.6 KB | — | 5.5 KB | — |
menu |
primitive | 14.2 KB | — | 16.3 KB | — | 64.5 KB | — |
modal |
primitive | 1.7 KB | — | 2.0 KB | — | 6.7 KB | — |
rail |
primitive | 534 B | — | 695 B | — | 1.5 KB | — |
segment |
primitive | 3.1 KB | — | 3.7 KB | — | 19.7 KB | — |
spinner |
primitive | 1.8 KB | — | 2.1 KB | — | 8.0 KB | — |
table |
primitive | 555 B | — | 692 B | — | 1.3 KB | — |
brotli q11 · gzip l9 · vs main · fresh build both sides · 58s
Correctness: nested pragma regions no longer crash the editor (sorted, outermost-wins decorations), orphaned markers hide, expanded folds are keyed by mapped positions, a fragment containing <header> is not a document, whole-project resets outrank per-file language-service pins, stale builds can't emit buildDone or resurrect old files through the send retry, ack listeners clean up on timeout, recovery failures surface, re-opening the current file applies external content, and the tooling worker URL follows the sandbox scope. The language service now ships a concatenated lib.d.ts (es2022 + dom), so globals resolve in completions and diagnostics instead of producing phantom errors. Docs: build errors render in the preview instead of an eternal spinner, missing-session recovery is throttled, share links route through the engine codec (fflate dropped), and the playground-elements-era scriptTypes, dead CSS selectors, stale plan instructions, and an orphaned 8.9MB vendored TypeScript copy are gone. The package builds with the root build:packages pipeline.
Also adds a guestbook entry for the session.
🟢 Preview Ready for
|
| project | status | preview | logs |
|---|---|---|---|
docs |
🟢 Ready | Preview | logs |
mcp |
⚪ NA | — | — |
Run: #28677562656 · docs semantic-next-hh1gg7psf-semantic-ui.vercel.app
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The docs playground now runs on @semantic-ui/playground, a new package that owns what playground-elements did: builds, module resolution, sandbox serving, and the code editor. Upstream is frozen and its architecture fought us. Per-instance compile workers raced dev-server transforms (the one-winner bug), the service worker had documented wait-forever corners, and editor capabilities meant reaching into internals. The engine is built around the opposite choices: one shared tooling worker per page, fully materialized sessions with broadcast recovery, and an editor adapter whose extension points are the API.
The engine is headless. Files in, live preview URL and diagnostics out, so the same contract serves the docs UI, the REPL share links, and eventually agents rendering components for iteration.
Changes
packages/playground: PlaygroundProject, shared tooling worker, sandbox service worker, CodeMirror editor adapterno-completions)sui-hide/sui-foldcanonical,playground-*as aliases. Display-only, marker comments never visible, expanding a fold no longer mutates the documentRisk
6/10 — every example page, homepage preview, and the REPL sit on this path, though nothing in the published framework runtime changes. Failure modes worth a skeptical look:
$el.tooltip is not a functionconsole error appears in dev from Sidebar's collapsed-tooltip script. Production is clean. Believed pre-existing (Sidebar code untouched) but not verified against a main dev serverHow to Test
/examples/todo-list— folds (click the…), tab switching, edit code and watch the preview rebuild/examples/tailwind— wasm compilation in the sandbox, Use Panels layout/examples/signals— hidden<head>block (line numbers jump), console output panel/examples/cdn-authoring— literal hide markers in example source, live CDN inside the sandbox/docs/api/reactivity/array-helpers— 8 inline playgrounds on one page (the old race's worst case)/playground— open any example's View in Playground link, or paste an old share link{in an html file (SUI LSP), any local symbol prefix in a js file (TypeScript)npm run buildinpackages/playground, thennode docs/scripts/sync-sandbox.mjs